Micron Document
🎖️GitЯра🎖️


Displaying Raw • Download

core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/InlineMarkdown.kt 01cd54907d62cd90913d3d071b6bc240cae365ef (01cd5490) Text, 9.14 KB

T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787org.meshtastic.core.ui.component

Tff7b72import T7ee787org.intellij.markdown.MarkdownElementTypes
Tff7b72import T7ee787org.intellij.markdown.MarkdownTokenTypes
Tff7b72import T7ee787org.intellij.markdown.ast.ASTNode
Tff7b72import T7ee787org.intellij.markdown.flavours.gfm.GFMElementTypes
Tff7b72import T7ee787org.intellij.markdown.flavours.gfm.GFMFlavourDescriptor
Tff7b72import T7ee787org.intellij.markdown.flavours.gfm.GFMTokenTypes
Tff7b72import T7ee787org.intellij.markdown.parser.MarkdownParser

T8b949e/**
* Parses the lightweight **inline** markdown subset shared with the iOS client — `**bold**`, `*italic*`,
* `~~strikethrough~~`, `` `code` `` and `[label](url)` — into a delimiter-stripped [InlineMarkdownResult.displayText]
* plus display-space [StyleSpan]s and [LinkSpan]s.
*
* Inline-only, matching iOS `AttributedString(markdown: .inlineOnlyPreservingWhitespace)`: block constructs (headings,
* lists, block quotes, fenced code, tables, images) are NOT interpreted — their markers survive as literal text because
* only the delimiter tokens that are direct children of a recognised inline element are removed. Whitespace and
* newlines are preserved. Malformed or unpaired markup degrades to literal text and never throws.
*
* The result is consumed by [AutoLinkText], which layers `@mention` and bare URL/email/phone links over the same
* [InlineMarkdownResult.displayText].
*/
Tff7b72fun Td2a8ffparseInlineMarkdownTb4b4b4(Te6edf3sourceTb4b4b4: Tffa657StringTb4b4b4)Tb4b4b4: Te6edf3InlineMarkdownResult Tb4b4b4{
T8b949e// Empty input or a parser failure (assertions are disabled, but stay total regardless) → literal text, no spans.
Tff7b72val Te6edf3tree Tff7b72= Tff7b72if Tb4b4b4(Te6edf3sourceTb4b4b4.Te6edf3isEmptyTb4b4b4(Tb4b4b4)Tb4b4b4) Tff7b72null Tff7b72else Te6edf3runCatching Tb4b4b4{ Te6edf3parserTb4b4b4.Te6edf3buildMarkdownTreeFromStringTb4b4b4(Te6edf3sourceTb4b4b4) Tb4b4b4}Tb4b4b4.Te6edf3getOrNullTb4b4b4(Tb4b4b4)
Tff7b72return Te6edf3treeTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3InlineMarkdownVisitorTb4b4b4(Te6edf3sourceTb4b4b4)Tb4b4b4.Te6edf3buildTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4}
Tff7b72?: Te6edf3InlineMarkdownResultTb4b4b4(Te6edf3sourceTb4b4b4, Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4)
Tb4b4b4}

T8b949e// assertionsEnabled = false → the parser recovers to a flat tree instead of throwing on malformed input.
Tff7b72private Tff7b72val Te6edf3parser Tff7b72= Te6edf3MarkdownParserTb4b4b4(Te6edf3GFMFlavourDescriptorTb4b4b4(Tb4b4b4)Tb4b4b4, Tff7b72falseTb4b4b4)

T8b949e/**
* Style spans over the RAW [source] (delimiters kept in place) for live in-field styling. Unlike [parseInlineMarkdown]
* this does NOT strip delimiters — it reports each bold/italic/strikethrough/code element's raw content range so a
* text-field `OutputTransformation` can `addStyle` without changing the stored text. Links are not styled here.
*/
Tff7b72fun Td2a8ffinlineMarkdownStyleRangesTb4b4b4(Te6edf3sourceTb4b4b4: Tffa657StringTb4b4b4)Tb4b4b4: Te6edf3ListTff7b72<Te6edf3StyleSpanTff7b72> Tb4b4b4{
Tff7b72val Te6edf3hasDelimiter Tff7b72= Te6edf3sourceTb4b4b4.Te6edf3any Tb4b4b4{ Tffa657it Tff7b72=Tff7b72= Ta5d6ff'*' Tff7b72|Tff7b72| Tffa657it Tff7b72=Tff7b72= Ta5d6ff'~' Tff7b72|Tff7b72| Tffa657it Tff7b72=Tff7b72= Ta5d6ff'`' Tb4b4b4}
Tff7b72val Te6edf3tree Tff7b72=
Tb4b4b4(Tff7b72if Tb4b4b4(Te6edf3hasDelimiterTb4b4b4) Te6edf3runCatching Tb4b4b4{ Te6edf3parserTb4b4b4.Te6edf3buildMarkdownTreeFromStringTb4b4b4(Te6edf3sourceTb4b4b4) Tb4b4b4}Tb4b4b4.Te6edf3getOrNullTb4b4b4(Tb4b4b4) Tff7b72else Tff7b72nullTb4b4b4)
Tff7b72?: Tff7b72return Te6edf3emptyListTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3spans Tff7b72= Te6edf3mutableListOfTff7b72<Te6edf3StyleSpanTff7b72>Tb4b4b4(Tb4b4b4)
Te6edf3collectStyleRangesTb4b4b4(Te6edf3treeTb4b4b4, Te6edf3spansTb4b4b4)
Tff7b72return Te6edf3spans
Tb4b4b4}

Tff7b72private Tff7b72fun Td2a8ffcollectStyleRangesTb4b4b4(Te6edf3nodeTb4b4b4: Te6edf3ASTNodeTb4b4b4, Te6edf3spansTb4b4b4: Te6edf3MutableListTff7b72<Te6edf3StyleSpanTff7b72>Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3style Tff7b72=
Tff7b72when Tb4b4b4(Te6edf3nodeTb4b4b4.Te6edf3typeTb4b4b4) Tb4b4b4{
Te6edf3MarkdownElementTypesTb4b4b4.Te6edf3STRONG Tff7b72-Tff7b72> Te6edf3InlineStyleTb4b4b4.Te6edf3Bold
Te6edf3MarkdownElementTypesTb4b4b4.Te6edf3EMPH Tff7b72-Tff7b72> Te6edf3InlineStyleTb4b4b4.Te6edf3Italic
Te6edf3MarkdownElementTypesTb4b4b4.Te6edf3CODE_SPAN Tff7b72-Tff7b72> Te6edf3InlineStyleTb4b4b4.Te6edf3Code
Te6edf3GFMElementTypesTb4b4b4.Te6edf3STRIKETHROUGH Tff7b72-Tff7b72> Te6edf3InlineStyleTb4b4b4.Te6edf3Strikethrough
Tff7b72else Tff7b72-Tff7b72> Tff7b72null
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3style Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3content Tff7b72= Te6edf3nodeTb4b4b4.Te6edf3childrenTb4b4b4.Te6edf3filter Tb4b4b4{ Tff7b72!Tb4b4b4(Tffa657itTb4b4b4.Te6edf3childrenTb4b4b4.Te6edf3isEmptyTb4b4b4(Tb4b4b4) Tff7b72&Tff7b72& Tffa657itTb4b4b4.Te6edf3type Tff7b72in Te6edf3delimiterTokensTb4b4b4) Tb4b4b4}
Tff7b72val Te6edf3start Tff7b72= Te6edf3contentTb4b4b4.Te6edf3firstOrNullTb4b4b4(Tb4b4b4)Tff7b72?.Te6edf3startOffset
Tff7b72val Te6edf3end Tff7b72= Te6edf3contentTb4b4b4.Te6edf3lastOrNullTb4b4b4(Tb4b4b4)Tff7b72?.Te6edf3endOffset
Tff7b72if Tb4b4b4(Te6edf3start Tff7b72!Tff7b72= Tff7b72null Tff7b72&Tff7b72& Te6edf3end Tff7b72!Tff7b72= Tff7b72null Tff7b72&Tff7b72& Te6edf3end Tff7b72> Te6edf3startTb4b4b4) Te6edf3spansTb4b4b4.Te6edf3addTb4b4b4(Te6edf3StyleSpanTb4b4b4(Te6edf3start Te6edf3until Te6edf3endTb4b4b4, Te6edf3styleTb4b4b4)Tb4b4b4)
Tb4b4b4}
Te6edf3nodeTb4b4b4.Te6edf3childrenTb4b4b4.Te6edf3forEach Tb4b4b4{ Te6edf3collectStyleRangesTb4b4b4(Tffa657itTb4b4b4, Te6edf3spansTb4b4b4) Tb4b4b4}
Tb4b4b4}

T8b949e/** The five inline styles shared with iOS. */
Tff7b72enum Tff7b72class T56d364InlineStyle Tb4b4b4{
Te6edf3BoldTb4b4b4,
Te6edf3ItalicTb4b4b4,
Te6edf3StrikethroughTb4b4b4,
Te6edf3CodeTb4b4b4,
Te6edf3LinkTb4b4b4,
Tb4b4b4}

T8b949e/** A non-link inline style applied over a half-open [range] in display-space. */
Tff7b72data Tff7b72class T56d364StyleSpanTb4b4b4(Tff7b72val Te6edf3rangeTb4b4b4: Te6edf3IntRangeTb4b4b4, Tff7b72val Te6edf3styleTb4b4b4: Te6edf3InlineStyleTb4b4b4)

T8b949e/** A markdown link covering the display-space [range] of its label, pointing at [url]. */
Tff7b72data Tff7b72class T56d364LinkSpanTb4b4b4(Tff7b72val Te6edf3rangeTb4b4b4: Te6edf3IntRangeTb4b4b4, Tff7b72val Te6edf3urlTb4b4b4: Tffa657StringTb4b4b4)

T8b949e/** Output of [parseInlineMarkdown]: the stripped text plus spans, all in display-space offsets. */
Tff7b72data Tff7b72class T56d364InlineMarkdownResultTb4b4b4(Tff7b72val Te6edf3displayTextTb4b4b4: Tffa657StringTb4b4b4, Tff7b72val Te6edf3styleSpansTb4b4b4: Te6edf3ListTff7b72<Te6edf3StyleSpanTff7b72>Tb4b4b4, Tff7b72val Te6edf3linkSpansTb4b4b4: Te6edf3ListTff7b72<Te6edf3LinkSpanTff7b72>Tb4b4b4)

T8b949e/** Delimiter tokens removed when they are direct children of a recognised inline element. */
Tff7b72private Tff7b72val Te6edf3delimiterTokens Tff7b72=
Te6edf3setOfTb4b4b4(
Te6edf3MarkdownTokenTypesTb4b4b4.Te6edf3EMPHTb4b4b4,
Te6edf3MarkdownTokenTypesTb4b4b4.Te6edf3BACKTICKTb4b4b4,
Te6edf3MarkdownTokenTypesTb4b4b4.Te6edf3ESCAPED_BACKTICKSTb4b4b4,
Te6edf3GFMTokenTypesTb4b4b4.Te6edf3TILDETb4b4b4,
Tb4b4b4)

Tff7b72private Tff7b72class T56d364InlineMarkdownVisitorTb4b4b4(Tff7b72private Tff7b72val Te6edf3sourceTb4b4b4: Tffa657StringTb4b4b4) Tb4b4b4{
Tff7b72private Tff7b72val Te6edf3out Tff7b72= Te6edf3StringBuilderTb4b4b4(Tb4b4b4)
Tff7b72private Tff7b72val Te6edf3styleSpans Tff7b72= Te6edf3mutableListOfTff7b72<Te6edf3StyleSpanTff7b72>Tb4b4b4(Tb4b4b4)
Tff7b72private Tff7b72val Te6edf3linkSpans Tff7b72= Te6edf3mutableListOfTff7b72<Te6edf3LinkSpanTff7b72>Tb4b4b4(Tb4b4b4)

Tff7b72fun Td2a8ffbuildTb4b4b4(Te6edf3rootTb4b4b4: Te6edf3ASTNodeTb4b4b4)Tb4b4b4: Te6edf3InlineMarkdownResult Tb4b4b4{
Te6edf3visitTb4b4b4(Te6edf3rootTb4b4b4, Te6edf3emptySetTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72return Te6edf3InlineMarkdownResultTb4b4b4(Tff7b72outTb4b4b4.Te6edf3toStringTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3styleSpansTb4b4b4.Te6edf3toListTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3linkSpansTb4b4b4.Te6edf3toListTb4b4b4(Tb4b4b4)Tb4b4b4)
Tb4b4b4}

Tff7b72private Tff7b72fun Td2a8ffvisitTb4b4b4(Te6edf3nodeTb4b4b4: Te6edf3ASTNodeTb4b4b4, Te6edf3stylesTb4b4b4: Te6edf3SetTff7b72<Te6edf3InlineStyleTff7b72>Tb4b4b4) Tb4b4b4{
Tff7b72when Tb4b4b4(Te6edf3nodeTb4b4b4.Te6edf3typeTb4b4b4) Tb4b4b4{
Te6edf3MarkdownElementTypesTb4b4b4.Te6edf3STRONG Tff7b72-Tff7b72> Te6edf3visitStyledTb4b4b4(Te6edf3nodeTb4b4b4, Te6edf3stylesTb4b4b4, Te6edf3InlineStyleTb4b4b4.Te6edf3BoldTb4b4b4)

Te6edf3MarkdownElementTypesTb4b4b4.Te6edf3EMPH Tff7b72-Tff7b72> Te6edf3visitStyledTb4b4b4(Te6edf3nodeTb4b4b4, Te6edf3stylesTb4b4b4, Te6edf3InlineStyleTb4b4b4.Te6edf3ItalicTb4b4b4)

Te6edf3GFMElementTypesTb4b4b4.Te6edf3STRIKETHROUGH Tff7b72-Tff7b72> Te6edf3visitStyledTb4b4b4(Te6edf3nodeTb4b4b4, Te6edf3stylesTb4b4b4, Te6edf3InlineStyleTb4b4b4.Te6edf3StrikethroughTb4b4b4)

Te6edf3MarkdownElementTypesTb4b4b4.Te6edf3CODE_SPAN Tff7b72-Tff7b72> Te6edf3visitCodeSpanTb4b4b4(Te6edf3nodeTb4b4b4, Te6edf3stylesTb4b4b4)

Te6edf3MarkdownElementTypesTb4b4b4.Te6edf3INLINE_LINK Tff7b72-Tff7b72> Te6edf3visitLinkTb4b4b4(Te6edf3nodeTb4b4b4, Te6edf3stylesTb4b4b4)

T8b949e// Images are not interpreted (inline-only): render the raw source literally.
Te6edf3MarkdownElementTypesTb4b4b4.Te6edf3IMAGE Tff7b72-Tff7b72> Te6edf3emitRawTb4b4b4(Te6edf3nodeTb4b4b4, Te6edf3stylesTb4b4b4)

Tff7b72else Tff7b72-Tff7b72> Tff7b72if Tb4b4b4(Te6edf3nodeTb4b4b4.Te6edf3childrenTb4b4b4.Te6edf3isEmptyTb4b4b4(Tb4b4b4)Tb4b4b4) Te6edf3emitRawTb4b4b4(Te6edf3nodeTb4b4b4, Te6edf3stylesTb4b4b4) Tff7b72else Te6edf3nodeTb4b4b4.Te6edf3childrenTb4b4b4.Te6edf3forEach Tb4b4b4{ Te6edf3visitTb4b4b4(Tffa657itTb4b4b4, Te6edf3stylesTb4b4b4) Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72private Tff7b72fun Td2a8ffvisitStyledTb4b4b4(Te6edf3nodeTb4b4b4: Te6edf3ASTNodeTb4b4b4, Te6edf3stylesTb4b4b4: Te6edf3SetTff7b72<Te6edf3InlineStyleTff7b72>Tb4b4b4, Te6edf3styleTb4b4b4: Te6edf3InlineStyleTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3next Tff7b72= Te6edf3styles Tff7b72+ Te6edf3style
Te6edf3nodeTb4b4b4.Te6edf3childrenTb4b4b4.Te6edf3forEach Tb4b4b4{ Te6edf3child Tff7b72-Tff7b72>
T8b949e// Skip the leaf open/close markers; recurse everything else (content may itself be styled/nested).
Tff7b72if Tb4b4b4(Te6edf3childTb4b4b4.Te6edf3childrenTb4b4b4.Te6edf3isEmptyTb4b4b4(Tb4b4b4) Tff7b72&Tff7b72& Te6edf3childTb4b4b4.Te6edf3type Tff7b72in Te6edf3delimiterTokensTb4b4b4) Tff7b72returnTf0883e@forEach
Te6edf3visitTb4b4b4(Te6edf3childTb4b4b4, Te6edf3nextTb4b4b4)
Tb4b4b4}
Tb4b4b4}

Tff7b72private Tff7b72fun Td2a8ffvisitCodeSpanTb4b4b4(Te6edf3nodeTb4b4b4: Te6edf3ASTNodeTb4b4b4, Te6edf3stylesTb4b4b4: Te6edf3SetTff7b72<Te6edf3InlineStyleTff7b72>Tb4b4b4) Tb4b4b4{
T8b949e// A code span's content is literal and never re-interpreted, so emit everything between the backtick runs
T8b949e// as ONE contiguous chunk — the lexer may split the inner text (e.g. a literal `*`) into several tokens,
T8b949e// but it must render as a single monospace span.
Tff7b72val Te6edf3content Tff7b72=
Te6edf3nodeTb4b4b4.Te6edf3childrenTb4b4b4.Te6edf3filter Tb4b4b4{
Tffa657itTb4b4b4.Te6edf3type Tff7b72!Tff7b72= Te6edf3MarkdownTokenTypesTb4b4b4.Te6edf3BACKTICK Tff7b72&Tff7b72& Tffa657itTb4b4b4.Te6edf3type Tff7b72!Tff7b72= Te6edf3MarkdownTokenTypesTb4b4b4.Te6edf3ESCAPED_BACKTICKS
Tb4b4b4}
Tff7b72val Te6edf3startOffset Tff7b72= Te6edf3contentTb4b4b4.Te6edf3firstOrNullTb4b4b4(Tb4b4b4)Tff7b72?.Te6edf3startOffset Tff7b72?: Tff7b72return
Tff7b72val Te6edf3endOffset Tff7b72= Te6edf3contentTb4b4b4.Te6edf3lastTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3endOffset
Tff7b72val Te6edf3start Tff7b72= Tff7b72outTb4b4b4.Te6edf3length
Tff7b72outTb4b4b4.Te6edf3appendTb4b4b4(Te6edf3sourceTb4b4b4, Te6edf3startOffsetTb4b4b4, Te6edf3endOffsetTb4b4b4)
Tff7b72val Te6edf3end Tff7b72= Tff7b72outTb4b4b4.Te6edf3length
Tff7b72if Tb4b4b4(Te6edf3end Tff7b72> Te6edf3startTb4b4b4) Tb4b4b4{
Tb4b4b4(Te6edf3styles Tff7b72+ Te6edf3InlineStyleTb4b4b4.Te6edf3CodeTb4b4b4)Tb4b4b4.Te6edf3forEach Tb4b4b4{ Te6edf3style Tff7b72-Tff7b72>
Tff7b72if Tb4b4b4(Te6edf3style Tff7b72!Tff7b72= Te6edf3InlineStyleTb4b4b4.Te6edf3LinkTb4b4b4) Te6edf3styleSpansTb4b4b4.Te6edf3addTb4b4b4(Te6edf3StyleSpanTb4b4b4(Te6edf3start Te6edf3until Te6edf3endTb4b4b4, Te6edf3styleTb4b4b4)Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72private Tff7b72fun Td2a8ffvisitLinkTb4b4b4(Te6edf3nodeTb4b4b4: Te6edf3ASTNodeTb4b4b4, Te6edf3stylesTb4b4b4: Te6edf3SetTff7b72<Te6edf3InlineStyleTff7b72>Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3linkText Tff7b72= Te6edf3nodeTb4b4b4.Te6edf3childrenTb4b4b4.Te6edf3firstOrNull Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3type Tff7b72=Tff7b72= Te6edf3MarkdownElementTypesTb4b4b4.Te6edf3LINK_TEXT Tb4b4b4}
Tff7b72val Te6edf3destination Tff7b72= Te6edf3nodeTb4b4b4.Te6edf3childrenTb4b4b4.Te6edf3firstOrNull Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3type Tff7b72=Tff7b72= Te6edf3MarkdownElementTypesTb4b4b4.Te6edf3LINK_DESTINATION Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3linkText Tff7b72=Tff7b72= Tff7b72null Tff7b72|Tff7b72| Te6edf3destination Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
T8b949e// Malformed link — render literally.
Tff7b72if Tb4b4b4(Te6edf3nodeTb4b4b4.Te6edf3childrenTb4b4b4.Te6edf3isEmptyTb4b4b4(Tb4b4b4)Tb4b4b4) Te6edf3emitRawTb4b4b4(Te6edf3nodeTb4b4b4, Te6edf3stylesTb4b4b4) Tff7b72else Te6edf3nodeTb4b4b4.Te6edf3childrenTb4b4b4.Te6edf3forEach Tb4b4b4{ Te6edf3visitTb4b4b4(Tffa657itTb4b4b4, Te6edf3stylesTb4b4b4) Tb4b4b4}
Tff7b72return
Tb4b4b4}
Tff7b72val Te6edf3url Tff7b72= Te6edf3sourceTb4b4b4.Te6edf3substringTb4b4b4(Te6edf3destinationTb4b4b4.Te6edf3startOffsetTb4b4b4, Te6edf3destinationTb4b4b4.Te6edf3endOffsetTb4b4b4)
Tff7b72val Te6edf3start Tff7b72= Tff7b72outTb4b4b4.Te6edf3length
Te6edf3linkTextTb4b4b4.Te6edf3childrenTb4b4b4.Te6edf3forEach Tb4b4b4{ Te6edf3child Tff7b72-Tff7b72>
T8b949e// LINK_TEXT wraps its content in `[` … `]`; drop the brackets, keep (and style) the label.
Tff7b72if Tb4b4b4(Te6edf3childTb4b4b4.Te6edf3type Tff7b72=Tff7b72= Te6edf3MarkdownTokenTypesTb4b4b4.Te6edf3LBRACKET Tff7b72|Tff7b72| Te6edf3childTb4b4b4.Te6edf3type Tff7b72=Tff7b72= Te6edf3MarkdownTokenTypesTb4b4b4.Te6edf3RBRACKETTb4b4b4) Tff7b72returnTf0883e@forEach
Te6edf3visitTb4b4b4(Te6edf3childTb4b4b4, Te6edf3stylesTb4b4b4)
Tb4b4b4}
Tff7b72val Te6edf3end Tff7b72= Tff7b72outTb4b4b4.Te6edf3length
Tff7b72if Tb4b4b4(Te6edf3end Tff7b72> Te6edf3startTb4b4b4) Te6edf3linkSpansTb4b4b4.Te6edf3addTb4b4b4(Te6edf3LinkSpanTb4b4b4(Te6edf3start Te6edf3until Te6edf3endTb4b4b4, Te6edf3urlTb4b4b4)Tb4b4b4)
Tb4b4b4}

Tff7b72private Tff7b72fun Td2a8ffemitRawTb4b4b4(Te6edf3nodeTb4b4b4: Te6edf3ASTNodeTb4b4b4, Te6edf3stylesTb4b4b4: Te6edf3SetTff7b72<Te6edf3InlineStyleTff7b72>Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3start Tff7b72= Tff7b72outTb4b4b4.Te6edf3length
Tff7b72outTb4b4b4.Te6edf3appendTb4b4b4(Te6edf3sourceTb4b4b4, Te6edf3nodeTb4b4b4.Te6edf3startOffsetTb4b4b4, Te6edf3nodeTb4b4b4.Te6edf3endOffsetTb4b4b4)
Tff7b72val Te6edf3end Tff7b72= Tff7b72outTb4b4b4.Te6edf3length
Tff7b72if Tb4b4b4(Te6edf3end Tff7b72> Te6edf3startTb4b4b4) Tb4b4b4{
Te6edf3stylesTb4b4b4.Te6edf3forEach Tb4b4b4{ Te6edf3style Tff7b72-Tff7b72> Tff7b72if Tb4b4b4(Te6edf3style Tff7b72!Tff7b72= Te6edf3InlineStyleTb4b4b4.Te6edf3LinkTb4b4b4) Te6edf3styleSpansTb4b4b4.Te6edf3addTb4b4b4(Te6edf3StyleSpanTb4b4b4(Te6edf3start Te6edf3until Te6edf3endTb4b4b4, Te6edf3styleTb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Served by rngit 1.5.0 - Generated in 0.08s